package de.tud.binpacking.instance;

import java.io.BufferedReader;
import java.io.DataInputStream;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.InputStreamReader;
import java.util.LinkedList;
import java.util.List;

import de.tud.binpacking.data.Item;
import de.tud.binpacking.data.Order;

public class Instance {

	// Instance generation parameters (Settings)
	private int noRows, noCells, noOrders, noAisles;
	private int capacity;

	// lengths
	private double cellLength, cellWidth, aisleWidth;
	private double distDepotAisle;
	private double distBetweenAisles;
	private double aisleLength;
	private double distToFirstItem;
	private double maxLength;

	private List<Order> orders = new LinkedList<Order>();

	/**
	 * This contructor reads the instance files
	 * @param filename The filename
	 * @throws IOException 
	 * @throws FileNotFoundException 
	 */
	public Instance(String instancePath, String settingsPath) throws FileNotFoundException, IOException {
		loadInstance(instancePath);
		loadSettings(settingsPath);
	}

	private boolean loadInstance(String instancePath) throws IOException, FileNotFoundException {

		String line = "";
		String tokens[];

		FileInputStream fstream = new FileInputStream(instancePath);
		DataInputStream in = new DataInputStream(fstream);
		BufferedReader inputStream = new BufferedReader(new InputStreamReader(in));

		Order order = null;
		List<Item> items = null;

		//read instace file line-by-line
		while ((line = inputStream.readLine()) != null) {

			line = line.trim().replaceAll("\\s+", " ");
			tokens = line.split(" ");

			if (line.contains("Order")) {

				if(order != null){
					order.setItems(items);
					orders.add(order);
				}

				order = new Order(this);
				order.setId(Integer.parseInt(tokens[1]));
				items = new LinkedList<Item>();

				// Create the Order
				// tokens[1] = order number
				// tokens[5] = number of items in this order

			}

			if (line.contains("Aisle")) {
				// Create the item
				// tokens[0] = item number
				// tokens[2] = the aisle of the item
				// tokens[4] = the location within the aisle
				items.add(new Item(Integer.parseInt(tokens[0]), Integer.parseInt(tokens[2]), Integer.parseInt(tokens[4])));
			}
		}
		order.setItems(items);
		orders.add(order);
		in.close();

		return true;
	}

	/**
	 * This method reads the settings file
	 * @param settingsPath The filename
	 * @return true if reading was successful
	 */
	private boolean loadSettings(String settingsPath) throws IOException, FileNotFoundException {

		String line = "";
		String tokens[];

		FileInputStream fstream = new FileInputStream(settingsPath);
		DataInputStream in = new DataInputStream(fstream);
		BufferedReader inputStream = new BufferedReader(
				new InputStreamReader(in));

		while ((line = inputStream.readLine()) != null) {

			line = line.trim().replaceAll("\\s+", " ");
			tokens = line.split(" ");

			if (line.contains("no_orders"))
				noOrders = Integer.valueOf(tokens[1]);

			if (line.contains("no_aisles")) {
				noRows = Integer.valueOf(tokens[1]);
				noAisles = noRows / 2;
			}

			if (line.contains("no_cells"))
				noCells = Integer.valueOf(tokens[1]);

			if (line.contains("cell_lengt"))
				cellLength = Double.valueOf(tokens[1]);

			if (line.contains("cell_width"))
				cellWidth = Double.valueOf(tokens[1]);

			if (line.contains("aisle_widt"))
				aisleWidth = Double.valueOf(tokens[1]);

			if (line.contains("dis_ais_wa"))
				distDepotAisle = Double.valueOf(tokens[1]);

			if (line.contains("m_no_a_p_b"))
				capacity = Integer.valueOf(tokens[1]);

		}

		//length of a vertical aisle
		aisleLength = noCells * cellLength + aisleWidth;

		//distance between two vertical aisles
		distBetweenAisles = 2 * cellWidth + aisleWidth;

		//distance to first item from horizontal aisle
		distToFirstItem = aisleWidth / 2 + cellLength / 2;

		//max distance according to sshape (traverse all aisles entirely)
		maxLength = noRows * aisleLength + 2 * (noRows - 1)
				* distBetweenAisles + distDepotAisle * 2;

		in.close();

		return true;
	}

	/* ************** BEGIN GETTERS **************** */

	/**
	 * @return the orders
	 */
	public List<Order> getOrders() {
		return orders;
	}

	/**
	 * @return the no_aisles
	 */
	public int getNoRows() {
		return noRows;
	}

	/**
	 * @return the no_cells
	 */
	public int getNoCells() {
		return noCells;
	}

	/**
	 * @return the no_orders
	 */
	public int getNoOrders() {
		return noOrders;
	}

	/**
	 * @return the capacity
	 */
	public int getCapacity() {
		return capacity;
	}

	/**
	 * @return the dist_depot_aisle
	 */
	public double getDistDepotAisle() {
		return distDepotAisle;
	}

	/**
	 * @return the distBetweenAisles
	 */
	public double getDistBetweenAisles() {
		return distBetweenAisles;
	}

	/**
	 * @return the aisleLength
	 */
	public double getAisleLength() {
		return aisleLength;
	}

	/**
	 * @return the cellLength
	 */
	public double getCellLength() {
		return cellLength;
	}

	/**
	 * @return the distToFirstItem
	 */
	public double getDistToFirstItem() {
		return distToFirstItem;
	}

	/**
	 * @return the maxLength
	 */
	public double getMaxLength() {
		return maxLength;
	}

	public int getNoAisles() {
		return noAisles;
	}

}